﻿import string, math
import random
################################
#Ипользывание Class = Class(size of map) ;while 1: if done= Class.gen_new_player(): break;

class Map: 
    
    size=0
    map={}
    violet={}
    gen_points={}
    plasts=0
    points_for_plast=40
    
   
    def __init__(self,size,levels):
        
        self.size=size
        self.levels=levels=levels+1
        self.map=self.gen_empty_map()
        
        max_rounds_per_level=int(abs((size*size/(self.points_for_plast))/1.5))#прдумать более хитрый способ
        for level in range(0,levels):
            self.violet[level]={}
            self.gen_points[level]={}
            self.gen_points[level][0,0]=0
            
            ###создаем уровень
            for round in range(0, max_rounds_per_level):
                done=False
                while(not done):
                    done=self.gen_new_plast(level)
                    
            
        print "Map OK!"
    
    #рисует озеро по алгоритму пляера
    def make_dira(self,size,level):
        blue={}                                     #массив содержаший colors blue
        red={}  
        violet=self.violet[level]
        point_to_gen=random.sample(self.gen_points[level],1) #выбираем где генерить
        del self.gen_points[level][point_to_gen[0]]        
        blue[point_to_gen[0]]=1
        ne_nashel=0
        xod=0;                                      #число ходов , жксперментальная перменая
        temp_map=self.map[level]
        while xod<=size:
            xodka=xod
            point=random.sample(blue,1)         #выбираем рандомный х,y
            point=point[0]
            x=point[0]
            y=point[1]                          #(невероятные процедуры)
            #выбор из четырех влево , вверх, вправо, вниз
            sum=0#проврки точки на то что она не безнадежна
            if (x-1,y) in blue or (x-1,y) in red or (x-1,y) in temp_map==1 or temp_map.get(x-1,y)==None:
                sum=sum+1
            if (x,y+1) in blue or (x,y+1) in red or (x,y+1) in temp_map==1 or temp_map.get(x,y+1)==None:
                sum=sum+1
            if (x+1,y) in blue or (x+1,y) in red or (x+1,y) in temp_map==1 or temp_map.get(x+1,y)==None:
                sum=sum+1
            if (x,y-1) in blue or (x,y-1) in red or (x,y-1) in temp_map==1 or temp_map.get(x,y-1)==None:
                sum=sum+1
            
            if sum==4:
                red[x,y]=1
                del blue[x,y]
                continue
            
            a=random.randint(1,4)
            if a==1:
                if (x-1,y) not in blue and (x-1,y) not in red and (x-1,y) in temp_map<>1 and (x-1,y) not in violet and temp_map.get(x-1,y)<>None:
                    blue[x-1,y]=1
                    xod+=1
            elif a==2:
                if (x,y+1) not in blue and (x,y+1)  not in red and (x,y+1)  in temp_map<>1 and (x,y+1) not in violet and temp_map.get(x,y+1)<>None:
                    blue[x,y+1]=1
                    xod+=1
            elif a==3:
                if (x+1,y) not in blue and (x+1,y)  not in red and (x+1,y) in temp_map<>1 and (x+1,y) not in violet and temp_map.get(x+1,y)<>None:
                    blue[x+1,y]=1
                    xod+=1
            elif a==4:
                if (x,y-1) not in blue and (x,y-1)  not in red and (x,y-1) in temp_map<>1 and (x,y-1) not in violet  and temp_map.get(x,y-1)<>None:
                    blue[x,y-1]=1
                    xod+=1
            if xod==xodka:
                ne_nashel+=1
            else:
                ne_nashel=0
            if ne_nashel>30:
                return False
          
        for point in blue:
            self.violet[level][point]=1
        for point in red:
            self.violet[level][point]=1
        return True
        
            
    def gen_new_plast(self,level):#функция создает нового плеера в точке х и у
        ########config/help#########
        #red=badblock=dont try this 3
        #white=empty 0
        #black=zaniato 1
        #blue=может быть как поинт from 2
        #violet=озеро
        points_for_plast=self.points_for_plast
        if self.plasts % 7==0 and self.plasts>5:
            while 1:
                done=self.make_dira(points_for_plast,level)
                if done:
                    break
        blue={}                                     #массив содержаший colors blue
        red={}
        ne_nashel=0
        violet=self.violet[level]
        
        point_to_gen=random.sample(self.gen_points[level],1) #выбираем где генерить
        del self.gen_points[level][point_to_gen[0]]        
        blue[point_to_gen[0]]=1
        
        xod=0;                                      #число ходов , жксперментальная перменая
        temp_map=self.map[level]                               #вот тут то мы и будем сотроить новую землю, что бы не резать на живом
    
        #lets go
        while xod<=points_for_plast:
            point=random.sample(blue,1)         #выбираем рандомный х,y
            point=point[0]
            x=point[0]
            y=point[1]
            xodka=xod                      #(невероятные процедуры)
            #выбор из четырех влево , вверх, вправо, вниз
            sum=0#проврки точки на то что она не безнадежна
            if (x-1,y) in blue or (x-1,y) in red or (x-1,y) in temp_map==1 or temp_map.get(x-1,y)==None:
                sum=sum+1
            if (x,y+1) in blue or (x,y+1) in red or (x,y+1) in temp_map==1 or temp_map.get(x,y+1)==None:
                sum=sum+1
            if (x+1,y) in blue or (x+1,y) in red or (x+1,y) in temp_map==1 or temp_map.get(x+1,y)==None:
                sum=sum+1
            if (x,y-1) in blue or (x,y-1) in red or (x,y-1) in temp_map==1 or temp_map.get(x,y-1)==None:
                sum=sum+1
            
            if sum==4:
                red[x,y]=1
                del blue[x,y]
                continue
            
            a=random.randint(1,4)
            if a==1:
                if (x-1,y) not in blue and (x-1,y) not in red and (x-1,y) in temp_map<>1 and (x-1,y) not in violet and temp_map.get(x-1,y)<>None:
                    blue[x-1,y]=1
                    xod+=1
            elif a==2:
                if (x,y+1) not in blue and (x,y+1)  not in red and (x,y+1)  in temp_map<>1 and (x,y+1) not in violet and temp_map.get(x,y+1)<>None:
                    blue[x,y+1]=1
                    xod+=1
            elif a==3:
                if (x+1,y) not in blue and (x+1,y)  not in red and (x+1,y) in temp_map<>1 and (x+1,y) not in violet and temp_map.get(x+1,y)<>None:
                    blue[x+1,y]=1
                    xod+=1
            elif a==4:
                if (x,y-1) not in blue and (x,y-1)  not in red and (x,y-1) in temp_map<>1 and (x,y-1) not in violet and temp_map.get(x,y-1)<>None:
                    blue[x,y-1]=1
                    xod+=1
            if xod==xodka:
                ne_nashel+=1
            else:
                ne_nashel=0
            if ne_nashel>30:
                return False 
        #пост обработка(нахождения новых возможных точек генерации,перегон верменой карты в реальную)
        #temp_map={}
        points=self.find_centers(blue,temp_map,level)
        if(points): 
            self.gen_points[level]=points
            
        for point in blue:
            self.map[level][point]=1
            temp_map[point]=1
        for point in red:
            self.map[level][point]=1
            temp_map[point]=1  
      
        self.plasts+=1
        return True
        
    
    def gen_empty_map(self):#генерит чистую мапу только вода
        ########config#########
        start_point_x=start_point_y=0
        
        ####sun_is_shining#####
        map_size=self.size
        levels=self.levels
        #generim more
        self.granica_niz=-(map_size/2)
        self.granica_verh=map_size/2
        map={}
        for z in range(0,levels):
            map[z]={}
            for x in range(self.granica_niz, self.granica_verh):
                for y in range(self.granica_niz,self.granica_verh):
                    map[z][x,y]=0
        return map
    
    def find_centers(self,blue,map,level):#ищет будущие точки генерации
        left_x=left_y=right_x=right_y=top_x=top_y=bot_x=bot_y=0
        
        ##проверка старых точек
        points_to_delet=[]
        for point in self.gen_points[level]:
            if map[point]==1 or point in self.violet:
                points_to_delet.append(point)
        
        for point in points_to_delet:
            del self.gen_points[level][point]
            
        #находим самые высокие, левые правые нижние
        for point in blue:
            x,y=point
            
            #можем ли мы взять эти точки или они уже зашли за границу?
            if ( self.canWeGet(map, (x,y) ) ):
                if x<=left_x and map[x-1,y]<>1:
                    left_x=x
                    left_y=y
                elif x>=right_x and map[x+1,y]<>1:
                    right_x=x
                    right_y=y
                elif y<=bot_y and map[x,y-1]<>1:
                    bot_x=x
                    bot_y=y
                elif y>=top_y and map[x,y+1]<>1:
                    top_x=x
                    top_y=y
            else:
                return False
        
       
            
        self.gen_points[level][top_x,top_y+1]=0
        self.gen_points[level][bot_x,bot_y-1]=0
        self.gen_points[level][right_x+1,right_y]=0
        self.gen_points[level][left_x-1,left_y]=0
        return self.gen_points[level]
    
    def test(self):#test map on errors
        for level in range(0,self.levels):
            for point in self.map[level]:
                x,y=point
                if x> self.granica_verh or x<self.granica_niz:
                    print "karta vishla za granicu"
                if y> self.granica_verh or y<self.granica_niz:
                    print "karta vishla za granicu"
                       
    def canWeGet(self,map,point):
        x,y=point
        
        if (map.get((x-1,y))<>None and map.get((x+1,y))<>None and map.get((x,y-1))<>None and map.get((x,y+1))<>None):
            return True
        return False
    
    def to_positive(self,zone):
        pos={}
        half_map=self.size/2
        for point in zone:
            pos[point[0]+half_map, point[1]+half_map]=zone[point]
        return pos
    
    def draw_map(self,img_path="C:/map.png"):
         #делаем мапу позитивной, врубаем рок, и ресуем ее через пил
        from PIL import Image, ImageDraw
        for level in range(0,self.levels):
            
            map=self.map[level]
            violet=self.violet[level]
            map_pos=self.to_positive(map)
            violet=self.to_positive(violet)    
            map_img = Image.new("RGBA", (self.size*5,self.size*5), (1,1,200,100))
            draw = ImageDraw.Draw(map_img)
            for point in map_pos:
                if map_pos[point]==1:
                    color="green"
                    draw.rectangle([point[0]*5,point[1]*5,(point[0]*5)+5,(point[1]*5)+5],fill=color,outline="black") 
                else:
                    draw.rectangle([point[0]*5,point[1]*5,(point[0]*5)+5,(point[1]*5)+5],outline="black") 
            del draw
            map_img.save("C:/map_izo"+str(level)+".png", "PNG")
    
    def map_to_text(self):#old standart to send map
        str_map=""
        map=self.map
        map=self.to_positive(map)
        for point in map:
            if not map[point]==0:
                str_map=str_map+str(point[0])+"."+str(point[1])+"."+str(map[point])+";"
        return str_map
    

    
    def pathFind(self,xfrom,yfrom,xto,yto):#deikstra
    #spijeno http://www.delphikingdom.com/asp/viewitem.asp?catalogid=811
        p_map={}
        number=0            #kolvo zemli voobshe
        val=0
        #определим квадрат действий
        
        if xfrom>=xto:
            max_x=xfrom+5
            min_x=xto-5
        else:
            max_x=xto+5
            min_x=xfrom-5
        
        if yfrom>=yto:
            max_y=yfrom+5
            min_y=yto-5
        else:
            max_y=yto+5
            min_y=yfrom-5
        
        for x in range(min_x-1, max_x+1):
                for y in range(min_y-1,max_y+1): 
                    if self.map[x,y]==1:
                        p_map[x,y]=0
                        number+=1
                    else:
                        p_map[x,y]=-1
        
        p_map[xto,yto]=1  #finish
                
        for i in range(1,number+1):
            val+=1
            for x in range(min_x, max_x):
                for y in range(min_y,max_y):   
                    if p_map[x, y] == val:
                        if p_map[x + 1, y] == 0:
                            p_map[x + 1, y] = val + 1
                        if p_map[x - 1, y] ==0:
                            p_map[x - 1, y] = val + 1
                        if p_map[x, y + 1] ==0:
                            p_map[x, y + 1] = val + 1
                        if p_map[x, y - 1] == 0:
                            p_map[x, y - 1] = val + 1
                            
        if p_map[xfrom,yfrom]==0:#esli nputi net
            return False
        
        val=p_map[xfrom,yfrom]   
        x=xfrom
        y=yfrom
        path=""
        while (val >= 2):
            if p_map[x, y] == val:
                val-=1
            
                if p_map[x + 1, y] == val:
                    x+=1
                    path+="%s;%s&"%(x,y)
                else:
                    if p_map[x- 1, y] == val:
                        x-=1
                        path+="%s;%s&"%(x,y)
                    else: 
                        if p_map[x, y+ 1] == val:
                            y+=1
                            path+="%s;%s&"%(x,y)
                        else: 
                            if p_map[x, y - 1] == val: 
                                y-=1
                                path+="%s;%s&"%(x,y)
                                 
        return path[:-1]      